/**
 * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.ratel.tool;

import cn.ratel.kit.StrKit;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

// edit by iver
public class TypeConverter {
	private static String timeStampPattern = "yyyy-MM-dd HH:mm:ss";
	private static String datePattern = "yyyy-MM-dd";
	private static Map<Class<?>, Convert> converterMap = new HashMap<Class<?>, Convert>() {
		{
			put(Integer.class, Integer::parseInt);
			put(int.class, Integer::parseInt);

			put(Long.class, Long::parseLong);
			put(long.class, Long::parseLong);

			put(Double.class, Double::parseDouble);
			put(double.class, Double::parseDouble);

			put(Float.class, Float::parseFloat);
			put(float.class, Float::parseFloat);

			put(Boolean.class, Boolean::parseBoolean);
			put(boolean.class, Boolean::parseBoolean);

			put(java.util.Date.class, s -> {
				if (s.length() >= timeStampPattern.length()) {
					return new SimpleDateFormat(timeStampPattern).parse(s);
				} else {
					return new SimpleDateFormat(datePattern).parse(s);
				}
			});

			put(java.sql.Date.class, s -> {
				if (s.length() >= timeStampPattern.length()) {
					return new java.sql.Date(new SimpleDateFormat(timeStampPattern).parse(s).getTime());
				} else {
					return new java.sql.Date(new SimpleDateFormat(datePattern).parse(s).getTime());
				}
			});

			put(java.sql.Time.class, java.sql.Time::valueOf);

			put(java.sql.Timestamp.class, java.sql.Timestamp::valueOf);

			put(java.math.BigDecimal.class, java.math.BigDecimal::new);

			put(java.math.BigInteger.class, java.math.BigInteger::new);

			put(byte[].class, String::getBytes);
		}
	};

	private TypeConverter() {
	}

	public interface Convert {
		Object convert(String s) throws ParseException;
	}

	/**
	 * 波总：
	 * test for all types of mysql
	 * <p>
	 * 表单提交测试结果:
	 * 1: 表单中的域,就算不输入任何内容,也会传过来 "", 也即永远不可能为 null.
	 * 2: 如果输入空格也会提交上来
	 * 3: 需要考 model中的 string属性,在传过来 "" 时是该转成 null还是不该转换,
	 * 我想, 因为用户没有输入那么肯定是 null, 而不该是 ""
	 * <p>
	 * 注意: 1:当clazz参数不为String.class, 且参数s为空串blank的情况,
	 * 此情况下转换结果为 null, 而不应该抛出异常
	 * 2:调用者需要对被转换数据做 null 判断，参见 ModelInjector 的两处调用
	 */
	public static <T> T convert(Class<T> clazz, String s) {
		if (clazz == String.class) {
			return (T) s;
		}
		if (StrKit.isBlank(s) && clazz.isPrimitive()) {
			s = "0";
		}

		if (s == null) {
			return null;
		}

		Convert convert = converterMap.get(clazz);
		if (convert == null) {
			throw new RuntimeException("can not find matched convert to " + clazz.getName());
		} else {
			try {
				return (T) converterMap.get(clazz).convert(s);
			} catch (ParseException e) {
				throw new RuntimeException(String.format("can not convert %s to %s", s, clazz.getName()), e);
			}
		}
	}

}
